package org.rcgwt.client.ui.validator.impl;

import java.util.Date;
import java.util.Map;

import org.rcgwt.client.ui.validator.IChecker;
import org.rcgwt.client.ui.validator.IClientValidatorContext;
import org.rcgwt.client.ui.validator.messages.Severity;
import org.rcgwt.client.util.Pattern;
import org.rcgwt.client.util.PatternBuilder;

/**
 * A checker which checks an hour like 12:00PM (12H format) or 23:30 (24H
 * format)
 * 
 * @author Elian ORIOU
 * 
 */

@SuppressWarnings("deprecation")
public class HourChecker implements IChecker {
	private static String sepSign = "*";

	/* Patterns */
	private Pattern HOUR_12;
	private Pattern HOUR_24;
	private Pattern OTHER_HOUR;

	private final Map<String, String> parameters;

	private boolean isBothBorned = false;
	private boolean isMinBorned = false;
	private boolean isMaxBorned = false;
	private Date min;
	private Date max;

	private static Date currentDate = new Date();

	public HourChecker(Map<String, String> p) {
		parameters = p;

		HOUR_12 = Pattern.compile("^[01][0-9][" + sepSign
				+ "][012345][0-9](AM|PM)$");
		HOUR_24 = Pattern.compile("^[012][0-9][" + sepSign + "][012345][0-9]$");
		OTHER_HOUR = Pattern.compile("^[012][0-9][:][012345][0-9]$");

		// Separator Sign
		if (parameters.containsKey("hour.sepSign")) {
			sepSign = parameters.get("hour.sepSign");
			HOUR_12 = Pattern.compile(PatternBuilder.encode(
					"^[01][0-9][%%1][012345][0-9](AM|PM)$", sepSign));
			HOUR_24 = Pattern.compile(PatternBuilder.encode(
					"^[012][0-9][%%1][012345][0-9]$", sepSign));
		}
		// Min & Max attributes
		if (parameters.containsKey("hour.min")) {
			isMinBorned = true;
			String[] h = parameters.get("hour.min").split(sepSign);
			min = new Date();
			min.setHours(Integer.parseInt(h[0]));
			min.setMinutes(Integer.parseInt(h[1]));
		}
		if (parameters.containsKey("hour.max")) {
			isMaxBorned = true;
			String[] h = parameters.get("hour.max").split(sepSign);
			max = new Date();
			max.setHours(Integer.parseInt(h[0]));
			max.setMinutes(Integer.parseInt(h[1]));
		}
		if (isMinBorned == true && isMaxBorned == true) {
			isBothBorned = true;
		}
	}

	@Override
	public boolean check(IClientValidatorContext context, String s) {

		/* If the format parameters is specified */
		if (parameters != null & parameters.containsKey("hour.format")) {
			// Default hour format & separator-signs
			String hourFormat = parameters.get("hour.format");

			// 12h Hour Format
			if (HOUR_12.matches(s)) {
				int colonIndex = s.indexOf(sepSign);
				int hour = Integer.parseInt(s.substring(0, colonIndex));
				int minutes = Integer.parseInt(s.substring(colonIndex + 1));
				currentDate.setHours(hour);
				currentDate.setMinutes(minutes);

				if (hourFormat.equals("12") && hour <= 12) {
					if (isBothBorned == true) {
						if (currentDate.after(min) && currentDate.before(max)) {
							return true;
						} else {
							launchHourRangeError(context, min.toString(), max
									.toString());
							return false;
						}
					} else if (isMinBorned == true) {
						if (currentDate.after(min)) {
							return true;
						} else {
							launchHourMinError(context, min.toString());
							return false;
						}
					}
					if (isMaxBorned == true) {
						if (currentDate.before(max)) {
							return true;
						} else {
							launchHourMaxError(context, max.toString());
							return false;
						}
					}
					return true;
				} else {
					context.addMessage(context.getMessagesProvider()
							.FormatErrorShort(hourFormat + "h"), context
							.getMessagesProvider()
							.FormatError(hourFormat + "h"), Severity.ERROR);
					return false;
				}
			}
			// 24h Hour Format
			else if (HOUR_24.matches(s)) {

				int colonIndex = s.indexOf(sepSign);
				int hour = Integer.parseInt(s.substring(0, colonIndex));
				int minutes = Integer.parseInt(s.substring(colonIndex + 1));
				currentDate.setHours(hour);
				currentDate.setMinutes(minutes);

				if (hourFormat.equals("24") && hour < 24) {
					if (isBothBorned == true) {
						if (currentDate.after(min) && currentDate.before(max)) {
							return true;
						} else {
							launchHourRangeError(context, min.toString(), max
									.toString());
							return false;
						}
					} else if (isMinBorned == true) {
						if (currentDate.after(min)) {
							return true;
						} else {
							launchHourMinError(context, min.toString());
							return false;
						}
					}
					if (isMaxBorned == true) {
						if (currentDate.before(max)) {
							return true;
						} else {
							launchHourMaxError(context, max.toString());
							return false;
						}
					}
					return true;
				} else {
					context.addMessage(context.getMessagesProvider()
							.FormatErrorShort(hourFormat + "h"), context
							.getMessagesProvider()
							.FormatError(hourFormat + "h"), Severity.ERROR);
					return false;
				}
			}
		} else if (OTHER_HOUR.matches(s) == true) {
			return true;
		}
		context.addMessage(context.getMessagesProvider().StructureErrorShort(),
				context.getMessagesProvider().StructureError(), Severity.ERROR);
		return false;
	}

	private void launchHourRangeError(IClientValidatorContext context,
			String min, String max) {
		context.addMessage(context.getMessagesProvider()
				.InvalidHourRangeErrorShort(min, max), context
				.getMessagesProvider().InvalidHourRangeError(min, max),
				Severity.ERROR);
	}

	private void launchHourMinError(IClientValidatorContext context, String min) {
		context.addMessage(context.getMessagesProvider()
				.InvalidHourMinErrorShort(min), context.getMessagesProvider()
				.InvalidHourMinError(min), Severity.ERROR);
	}

	private void launchHourMaxError(IClientValidatorContext context, String max) {
		context.addMessage(context.getMessagesProvider()
				.InvalidHourMaxErrorShort(max), context.getMessagesProvider()
				.InvalidHourMaxError(max), Severity.ERROR);
	}

}
